package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"gitee.com/thubcc/p2pgit/classedpack"
	"gitee.com/thubcc/p2pgit/gitpack"
	"gitee.com/thubcc/p2pgit/some"
	"gitee.com/thubcc/p2pgit/types"
	"gitee.com/thubcc/p2pgit/utils"
	"github.com/a4a881d4/gitcrawling/packext"
	"gopkg.in/src-d/go-git.v4/plumbing"
)

var (
	argNewPack = flag.String("n", "../temp", "New Pack Dir")
	argURL     = flag.String("u", "http://localhost:8080", "server url")
	argNum     = flag.Int("c", 10, "number to dump")
	argGitPack = flag.String("g", "../temp", "Git Pack Dir")
	argWrite   = flag.Bool("w", false, "Write")
	argThread  = flag.Int("t", 32, "multi thread write")
)

var t = log.New(os.Stdout, "post:", 6)

func findFile() (r []string) {
	packext.DefaultFromDir(*argGitPack)
	for _, v := range packext.DefaultMap {
		r = append(r, strings.Replace(v, ".pack", ".idx", -1))
	}
	return
}

func objs() []types.Hash {
	gs, err := some.GeterFromDir(*argNewPack)
	if err != nil {
		fmt.Println("get geters from", *argNewPack, err)
		return []types.Hash{}
	}
	return some.Geter2Hashes(gs)
}

func write() {

	var fn = make(chan string, *argThread)
	var done = make(chan int)
	var do = func(worker int) (cerr error) {
		hs, err := some.HiterFromServer(*argURL)
		if err != nil {
			fmt.Println(err)
			return
		}
		cs, err := classedpack.NewAPI(*argURL, hs)
		if err != nil {
			fmt.Println(err)
			return
		}
		var gs types.SomeGeter
		gs = append(gs, cs)
		ps := types.NewRawer(some.Geter2Rawer(gs))
		if err := ps.Open(true); err != nil {
			t.Println("open client", err)
			t.Fatal()
		}
		for {
			select {
			case forTest := <-fn:
				t.Printf("%4d travel %s\n", worker, forTest)
				cerr = gitpack.TravelGitPackFile(forTest, some.NewPackCBForHTTPPost(gs))
				if cerr != nil {
					t.Println("error:", worker, forTest, cerr)
				}
			case <-done:
				return
			}
		}
	}
	for i := 0; i < *argThread; i++ {
		go do(i)
	}

	filenames := findFile()
	fmt.Println("find", len(filenames))

	for _, filename := range filenames {
		fn <- filename
	}
	for i := 0; i < 600; i++ {
		<-time.After(time.Second)
		if len(fn) == 0 {
			break
		}
	}

	fmt.Println("done", len(filenames), "left", len(fn))
	close(done)
}
func read(objs []types.Hash, gs types.SomeGeter) {
	var num = *argNum
	if num == -1 {
		num = len(objs)
	}
	p := utils.NewProgress("Read:", num)
	p.Every = 10000
	p.Init()
	defer p.End()

	for k, v := range objs {
		body, t, err := types.ResolveObj(gs, types.HashSelect(v))
		if err != nil {
			fmt.Println(err)
		}
		ghash := plumbing.ComputeHash(t, body)
		if types.Hash(ghash) != v {
			fmt.Println(k, v.String(), "!=", ghash.String())
		}
		if k > num {
			break
		}
		p.Done()
	}
}

func main() {
	flag.Parse()
	hs, err := some.HiterFromServer(*argURL)
	if err != nil {
		fmt.Println(err)
		return
	}
	cs, err := classedpack.NewAPI(*argURL, hs)
	if err != nil {
		fmt.Println(err)
		return
	}

	var gs types.SomeGeter
	gs = append(gs, cs)
	if *argWrite {
		write()
		t.Println("write done")
	} else {
		os := objs()
		t.Println("find done")
		read(os, gs)
		t.Println("read done")
	}
}
